Electronic devices, such as computer systems, typically communicate with audio devices through device drivers associated with the audio devices. For example, a computer system plays sound on a speaker by sending audio data to a device driver designed for the speaker. Similarly, a computer system captures audio information from a microphone by receiving audio data from the device driver associated with the microphone.
Various approaches may be used to handle the communication of audio information between client applications (“clients”) that use audio information and the device drivers of audio devices. For example, according to an interrupt-based approach, a direct connection is established between the driver and its client application. Any time the driver wants audio data from the client, the driver raises an interrupt, suspending other activity on the Central Processing Unit (“CPU”) of the computer system on which the client is running. Therefore, for a certain period of time, the driver is in control of the computer system. Also, constant use of the interrupt to communicate data entails a lot CPU overhead when communicating with multiple clients.
To avoid problems associated with the interrupt approach, decoupled multithreading is used. Under decoupled multi-threading, execution of a device driver is decoupled from execution of its client application by using separate threads of execution to execute the client application (“client threads”) and separate threads of execution to execute the device driver (“device threads”), and using a ring buffer to communicate data between the client application and the device driver.
Specifically, the device driver, being executed by a device thread, reads audio data from the ring buffer at a particular position in the ring buffer; the client application, being executed by a client thread, feeds audio data into the ring buffer at a point ahead of the device driver so that the device driver continues to have new audio data to read. Similarly, the device driver writes audio data into the ring buffer; the client application, in turn, reads audio data from the ring buffer at a rate to ensure that the device driver does not overwrite unread audio data.
To add data to the ring buffer, the client application writes a pre-arranged quantum of data to the ring buffer, referred to herein as a unit of buffering or buffer unit. An operation performed by the client application to add a buffer unit of data to a particular position in the ring buffer is referred to herein as a client write operation. A buffer unit holds audio representing sound for a period of time. The period of time is referred to herein as the duration of the buffer unit. If a buffer unit holds audio for 11 milliseconds of playback, the duration of the buffer unit is 11 milliseconds.
To add data to a particular position in the ring buffer where the device driver will read data, a client write operation is commenced a period of time in advance of the device driver reaching the position. There are various reasons for commencing the write operation in advance. For example, it takes a period of time for the client to generate and write the data. The length of the period depends on such factors on how long it takes for the client application to perform a write operation. Second, the position of the ring buffer from which the device driver is or will read data can only be tracked within a margin of error. The client application should be called a time period sufficiently in advance to allow the client application to complete writing the buffer unit of data at a particular position in the ring buffer position before the device driver reaches that position, with an allowance for the margin of error.
This offset period of time in advance represents how close a client may add data to the current position of the device in the ring buffer to have the device driver read the data and have it output as sound. Thus, the offset period of time represents the minimum latency between when a client write operation is commenced and when the data is read by the device driver.
Latency is an important measure of responsiveness. The greater the latency, the less responsive an audio system is. Other factors relevant to the latency in an audio system include the amount of time it takes a device to transfer the data from the computer to the device and the amount of time the device takes to translate the data into a perceivable form (e.g. converting digital audio into analog audio) once the data has reached the device.
To schedule client write operations, the offset period of time the operation must be commenced in advance of the current position of the reader is estimated and the estimate used to determine when to commence the client write operations. The estimate of this period of time is referred to herein as the client-side offset. For example, to add data at a particular position in the ring buffer, a client write operation is commenced no later than the client-side offset before the time the device reaches the position.
The client-side offset is estimated based on the assumption that, to perform a write operation to add a buffer unit of data to a ring buffer, the client application requires a time period equal to the buffer unit duration. Based on this assumption, the client-side offset is calculated so that it includes a buffer unit duration plus the margin of error for tracking the device driver's read position in the ring buffer.
Using the client-side offset to schedule client write operations renders the client-side offset a built-in latency. Because client write operations to add data to a certain position in the ring buffer are scheduled based on the client-side offset, the client-side offset is a scheduled latency that is always realized. Furthermore, if the client-side offset includes the buffer unit duration, the buffer unit duration becomes a built-in latency, regardless of how long execution of a client write operation actually takes.
Based on the foregoing, there is clearly a need for an approach for calculating a client-side offset that avoids the built-in latency attendant to using the buffer unit duration to schedule client write operations.